#include <iostream>
#include <memory>
#include <string>

using std::cout;
using std::endl;
using std::unique_ptr;
using std::shared_ptr;
using std::string;

/*
为什么return shared_ptr<Point> (this)的报错如下：
    (2,4)
    (2,4)
    sp.use_count()=2
    sp3.use_count()=1
    sp.get()=0x5600def49e70
    sp3.get()=0x5600def49e70
    ~Point()
    ~Point()
    free(): double free detected in tcache 2
    已放弃 (核心已转储)

1、shared_ptr<Point> (this)会创建一个智能指针临时对象，确实指向new Point(1,2)
    此时 shared_ptr<Point> sp3(sp->addPoint(sp2.get())); 
    调用拷贝构造函数，sp3和临时对象都指向new Point(1,2)，
    它们的count=2，get裸指针和sp一样都是new Point(1,2)的地址。
    之后临时对象销毁，sp3的引用计数为1，而sp和sp2是正确使用的，count=2
2、相当于 Point *pint = Point(1,2);
        shared_ptr<Point> sp(pint);
        shared_ptr<Point> sp2(pint);
    会析构两次~Point()，因为sp和sp2以为它们管理的是不同的两个pint，两个减为0，就析构两块空间。
    所以上面sp、sp3会析构两次~Point()，因为他俩以为管理的是不同的new Point(1,2)

3、当函数的参数是shared_ptr时，采用shared_from_this，避免二次释放

*/


class Point
: public std::enable_shared_from_this<Point>
{
public:
    Point(int ix,int iy)
    : _ix(ix)
    , _iy(iy)
    {
        cout<<"Point(int,int)"<<endl;
    }

    //Point *addPoint(Point *pt)
    shared_ptr<Point> addPoint(Point *pt)
    {
        _ix+=pt->_ix;
        _iy+=pt->_iy;

        //1、
        //return this;
        
        //2、
        return shared_ptr<Point>(this); 
        
        //3、因为要调用其他类的成员函数，所以最先想到继承
        //return shared_from_this();
    }

    void print(){
        cout<<"("<<_ix<<","<<_iy<<")"<<endl;
    }

    ~Point(){
        cout<<"~Point()"<<endl;
    }

private:
    int _ix;
    int _iy;
};

void test(){
    shared_ptr<Point> sp(new Point(1,2));
    sp->print();
    cout<<"sp.use_count()="<<sp.use_count()<<endl;
    cout<<"sp.get()="<<sp.get()<<endl;

    cout<<endl;
    shared_ptr<Point> sp2(new Point(3,4));
    sp2->print();
    cout<<"sp2.use_count()="<<sp2.use_count()<<endl;
    cout<<"sp2.get()="<<sp2.get()<<endl;
    sp2=sp;

    cout<<endl;
    //sp->addPoint(sp2.get());
    shared_ptr<Point> sp3(sp->addPoint(sp2.get())); 
    //参数是，一个指向Point类型的智能指针
    //1、如果返回的是sp的this(裸指针)，sp、sp3指向同一空间，但初始化不会增加引用计数
    //2、如果返回的是智能指针，则拷贝构造sp3，，但临时对象不能区分this和实际指向的new Point 
    //3、使用shared_from_this，返回共享所有权的*this，这样就会+1且不会销毁
    sp->print();
    sp3->print();
    cout<<"sp.use_count()="<<sp.use_count()<<endl;
    cout<<"sp3.use_count()="<<sp3.use_count()<<endl;
    cout<<"sp.get()="<<sp.get()<<endl;
    cout<<"sp3.get()="<<sp3.get()<<endl;    //sp、sp3地址相同，托管同一个堆空间
}

int main()
{   
    test();
    return 0;
}

